# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import cgi
import sys
import datetime
import time
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp.util import run_wsgi_app

import simplejson

class AppController(webapp.RequestHandler):
  """ this class handle all requests from /req and output json string.
  
  """

  def setConfig(self,config):
    self.configFile = config
    
  def setCommandModule(self,commands):
    self.commands = commands
  
  def get(self):
    self.handle()
    
  def post(self):
    self.handle()
    
  def handle(self):
    self.request.headers['CharacterEncoding'] = 'UTF-8'
    (ctn,vid,oid) = self.authendicate(self.request)
    
    self.config = ConfigFactory(self.configFile).load()
    self.context = AppContext(self.request,self.response,self.config)
    self.context.update({"ctn":ctn,"vid":vid,"oid":oid})
    
    commandName = self.request.get("cmd")
    command = CommandFactory(self.commands).load(commandName)
    
    result = command.executeWithContext(self.context)
    
    self.response.headers['CharacterEncoding'] = 'UTF-8'
    self.response.headers['Content-Type'] = 'text/plain'
    output = self.context["output"]
    
    self.response.out.write(BeanJsonConverter.convertToString(output))
	
  def authendicate(self,request):
    if(request.get("ctn") and request.get("vid") and request.get("oid")):
      return (request.get("ctn"),request.get("vid"),request.get("oid"));
    else:
      #TODO : is sytax right?
      raise AttributeError,"parameters not sufficient"
  
class AppContext(dict):
  """ this class include context used in command
  
  """
  def __init__(self,request,response,config):
    self.request = request
    self.response = response
    self.config = config
    
class ConfigFactory:
  """ this class read specific configuration of every container
  """
  def __init__(self,config):
    self.config = config
  
  def load(self,container="default"):
    return self.config[container]
  
class CommandFactory:
  """this class load command from catalog config file
  """
  def __init__(self,commands):
    self.commands = commands
  
  def load(self,commandName):
    try:
      command = getattr(self.commands,commandName + "Command")
      return command()
    except AttributeError:
      #TODO : look for catalog config
      c = getattr(self.commands,"catalog")
      command = getattr(self.commands,c[commandName] + "Command")
      return command()

class ResponseItem:
  def __init__(self):
    self.hasError = True
    self.data = None
    
class Message:
  def __init__(self,messageId,params):
    self.messageId = messageId
    self.params = params

class ModelEncoder(simplejson.JSONEncoder):
  """used to encode model object
  """
  def default(self, obj):
    if isinstance(obj, db.Model):
      return obj.__dict__['_entity']
    if isinstance(obj,ResponseItem):
      return obj.__dict__
    if isinstance(obj,Message):
      return obj.__dict__
    if isinstance(obj,datetime.datetime):
      ts = time.mktime(obj.timetuple())
      ts = int(ts * 1000 + obj.microsecond / 1000)
      return int(ts)
    
    return simplejson.JSONEncoder.default(self, obj)

class BeanJsonConverter:
  """ this class converter object to json string
  """
  @staticmethod
  def convertToString(obj):
    return simplejson.dumps(obj,cls=ModelEncoder)

class Command:
  NEXT = False
  END = True

  def pre(self,context):
    self.responseItem = ResponseItem()
    self.request = context.request
    self.response = context.response
    self.config = context.config
    self.context = context
    context["output"] = self.responseItem
    
    return self.NEXT
  
  def output(self,data):
    self.responseItem.data = data
  
  def hasError(self,flag):
    self.responseItem.hasError = flag
  
  def executeWithContext(self,context):
    if(self.pre(context) == self.NEXT):
      return self.execute()
    else:
      return self.END
  
  def execute(self):
    raise NotImplementedError
